﻿/**@author W意波 编写*/
#ifndef LK_TIME_
#define LK_TIME_
namespace LK
{
	/**
	@brief Time类表示时间长度
	@note 当把Time对象视为时刻时，其保存的是公元元年到该时刻的时间长度*/
	struct Time :virtual Object, virtual ICloneables
	{
	protected:
		/**
		@brief 获取公元元年至指定年月日总天数
		@param [传入]参数year表示指定的年份
		@param [传入]参数month表示指定的月份
		@param [传入]参数day表示指定的日
		@return 返回度过的天数*/
		static long long GetDays(unsigned year, unsigned int month, unsigned int day);
		/**
		@brief 根据年份和当年已过天数获取月份，输入的天数将变为日输出
		@param [传入]参数year用以指定年份
		@param [传入,写出]参数days用以传入已过天数和输出结果日
		@return 返回月份*/
		static unsigned int GetMonthByDaysInYear(unsigned year, unsigned int& days);
		/**
		@brief 设置当前的本地时刻
		@param [传入]参数now表示当前时刻，即公元元年元月1日0点到当前时刻的长度*/
		static void SetLocal(const Time& now);
		/**
		@brief 同时获取该对象所表示时刻的年份和当年的已过天数
		@param [写出]参数pday用以输出该时间对应日期在当年已过天数
		@return 返回该时间所在年份
		@note 该函数认为该对象表示时刻*/
		unsigned int GetYearAndDaysInYear(unsigned int*pday)const;
	public:
		/**@brief 通用基类方法*/
		BMETHODS(PTime, Time)
		/**@brief 交换*/
		void SwapWith(Time& x) { Swap(time, x.time); }
		/**@brief 产生一个浅表副本*/
		Time* Clone()const { return new Time(*this); }
		/**
		@brief 获取当前的本地时刻*/
		static Time GetLocal() { return GetLocalTick(); }
		static long long GetLocalTick();
#ifdef _WINDOWS
		/**@brief 获取CPU时钟*/
		static inline LARGE_INTEGER& CpuCounterReference()
		{
			static LARGE_INTEGER f = { 0 };
			QueryPerformanceCounter(&f);
			return f;
		}
#endif
		/**
		@brief 每微秒的时长*/
		const static long long EveryMicrosecond = 10;
		/**
		@brief 每毫秒时间长度*/
		const static long long EveryMillisecond = 10000;
		/**
		@brief 每秒时间长度*/
		const static long long EverySecond = 10000000;
		/**
		@brief 每分时间长度*/
		const static long long EveryMinute = 600000000;
		/**
		@brief 每小时时间长度*/
		const static long long EveryHour = 36000000000;
		/**
		@brief 每天时间长度*/
		const static long long EveryDay = 864000000000;
		/**
		@brief 每周时间长度*/
		const static long long EveryWeek = 6048000000000;
		/**
		@brief 获取该时间所在年份
		@note 该函数认为该对象表示时刻*/
		unsigned int GetYear()const;
		/**
		@brief 获取该时间所在月份
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMonth()const;
		/**
		@brief 获取该时间所在日
		@note 该函数认为该对象表示时刻*/
		unsigned int GetDay()const;
		/**
		@brief 获取该时间表示星期几（0代表星期天）
		@note 该函数认为该对象表示时刻*/
		unsigned int GetDayOfWeek()const;
		/**
		@brief 获取时
		@note 该函数认为该对象表示时刻*/
		unsigned int GetHour()const;
		/**
		@brief 获取分
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMinute()const;
		/**
		@brief 获取秒
		@note 该函数认为该对象表示时刻*/
		unsigned int GetSecond()const;
		/**
		@brief 获取毫秒
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMillisecond()const;
		/**
		@brief 获取微秒
		@note 该函数认为该对象表示时刻*/
		unsigned int GetMicrosecond()const;
		/**
		@brief 设置年
		@note 该函数认为该对象表示时刻*/
		void SetYear(unsigned int);
		/**
		@brief 设置月
		@note 该函数认为该对象表示时刻*/
		void SetMonth(unsigned int);
		/**
		@brief 设置日
		@note 该函数认为该对象表示时刻*/
		void SetDay(unsigned int);
		/**
		@brief 设置时
		@note 该函数认为该对象表示时刻*/
		void SetHour(unsigned int);
		/**
		@brief 设置分
		@note 该函数认为该对象表示时刻*/
		void SetMinute(unsigned int);
		/**
		@brief 设置秒
		@note 该函数认为该对象表示时刻*/
		void SetSecond(unsigned int);
		/**
		@brief 设置毫秒
		@note 该函数认为该对象表示时刻*/
		void SetMillisecond(unsigned int);
		/**
		@brief 设置微秒
		@note 该函数认为该对象表示时刻*/
		void SetMicrosecond(unsigned int);
		/**
		@brief 使用一个64位有符号数字来记录时间，单位100ns*/
		long long time;
		/**
		@brief 默认构造函数*/
		Time();
		/**
		@brief 从字符串构造*/
		Time(const PString&str);
		/**@brief 使用一个整数值来初始化*/
		Time(long long t);
#ifdef _WINDOWS
		/**
		@brief 使用一个WindowsAPI定义的系统时间来初始化*/
		Time(const ::SYSTEMTIME& t);
#endif
		/**
		@brief 使用一个标准库定义的系统时间来初始化*/
		Time(const ::tm& t);
		/**
		@brief 属性：当前时间*/
		static StaticProperty<Time> Now;
		/**
		@brief 获取该对象所示时长（天数，可能为负）*/
		int GetDays()const;
		/**
		@brief 获取该对象所示时长（小时数，可能为负）*/
		int GetHours()const;
		/**
		@brief 获取该对象所示时长（分数，可能为负）*/
		long long GetMinutes()const;
		/**
		@brief 获取该对象所示时长（秒数，可能为负）*/
		long long GetSeconds()const;
		/**
		@brief 获取该对象所示时长（毫秒数，可能为负）*/
		long long GetMilliseconds()const;
		/**
		@brief 获取该对象所示时长（微秒数，可能为负）*/
		long long GetMicroseconds()const;
		/**
		@brief 取时长，十分之一微秒为单位*/
		operator long long()const;
#ifdef _WINDOWS
		/**
		@brief 转换为WindowsAPI的系统时间*/
		operator ::SYSTEMTIME()const;
#endif
		/**
		@brief 转换为stl中的日期*/
		operator ::tm()const;

		/**@brief 重载算数运算符*/
		Time&operator+=(long long t) { time += t; return *this; }
		/**@brief 重载算数运算符*/
		Time&operator-=(long long t) { time -= t; return *this; }
		/**@brief 重载算数运算符*/
		Time&operator%=(long long t) { time %= t; return *this; }
		/**@brief 重载算数运算符*/
		Time&operator*=(long long t) { time *= t; return *this; }
		/**@brief 重载算数运算符*/
		Time&operator/=(long long t) { time /= t; return *this; }
		/**@brief 重载算数运算符*/
		Time friend operator+(const Time t1, const Time t2) { return Time(t1.time + t2.time); }
		/**@brief 重载算数运算符*/
		Time friend operator-(const Time t1, const Time t2) { return Time(t1.time - t2.time); }

		/**@brief 赋值运算*/
		Time& operator=(const Time& t);
		/**@brief 赋值运算*/
		Time& operator=(long long t);

		/**
		@brief 线程挂起一段时间
		@param [传入]参数t表示间隔时间长度
		@note 与Sleep不同，该方法相当于定时器，意为每隔时间t就放行一次，内部使用Sleep实现*/
		void Wait(const Time& t);

		/**
		@brief 到字符串的转换（时间长度），重写XBase::ToString()*/
		virtual PString ToString()const;
		/**
		@brief 到字符串的转换（格式化输出）
		@param [传入]参数str用以指定输出格式*/
		PString ToString(const PString&str)const;
#ifdef _CLR /**@brief 托管支持*/
		/**
		@brief 从托管的时间构造*/
		Time(System::DateTime^time);
		/**
		@brief 转换到托管的时间*/
		System::DateTime^ ToDateTime()const;
#endif
	};
	struct PTime : PObject
	{
	public:
		/**
		@brief 设置当前的本地时刻*/
		static void SetLocal(const PTime& now) { Time::Now = *now.Ptr(); }
		/**
		@brief 获取当前的本地时刻*/
		static PTime GetLocal()
		{
			return Time::GetLocalTick();
		}
		/**
		@brief 类型信息添加*/
		static void AddTypeInfo();
#ifdef _WINDOWS
		/**@brief 获取CPU时钟*/
		static inline LARGE_INTEGER& CpuCounterReference()
		{
			return Time::CpuCounterReference();
		}
#endif
		/**@brief 每微秒的时长*/
		const static long long EveryMicrosecond = 10;
		/**@brief 每毫秒时间长度*/
		const static long long EveryMillisecond = 10000;
		/**@brief 每秒时间长度*/
		const static long long EverySecond = 10000000;
		/**@brief 每分时间长度*/
		const static long long EveryMinute = 600000000;
		/**@brief 每小时时间长度*/
		const static long long EveryHour = 36000000000;
		/**@brief 每天时间长度*/
		const static long long EveryDay = 864000000000;
		/**@brief 每周时间长度*/
		const static long long EveryWeek = 6048000000000;
		PMETHODS(PTime, Time);
		/**@brief 从字符串构造*/
		PTime(const PString&str);
		/**@brief 使用一个整数值来初始化*/
		PTime(unsigned long long t) :PObject(new Time((long long)t)) {}
		PTime(long long t) :PObject(new Time(t)) {}
		PTime(unsigned long t) :PObject(new Time((long long)t)) {}
		PTime(long t) :PObject(new Time((long long)t)) {}
		PTime(unsigned int t) :PObject(new Time((long long)t)) {}
		PTime(int t) :PObject(new Time((long long)t)) {}
#ifdef _WINDOWS
		/**@brief 使用一个WindowsAPI定义的系统时间来初始化*/
		PTime(const ::SYSTEMTIME& t) : PObject(new Time(t)) {}
#endif
		/**@brief 使用一个标准库定义的系统时间来初始化*/
		PTime(const ::tm& t) : PObject(new Time(t)) {}
		/**
		@brief 属性：当前时间*/
		static StaticProperty<PTime> Now;
		/**@brief 取时长，十分之一微秒为单位（相对公元元年）*/
		operator long long()const { return *Ptr(); }
#ifdef _WINDOWS
		/**@brief 转换为WindowsAPI的系统时间*/
		operator ::SYSTEMTIME()const { return *Ptr(); }
#endif
		/**@brief 转换为标准库的系统时间*/
		operator ::tm()const { return *Ptr(); }
		/**@brief 重载算数运算符*/
		PTime&operator+=(long long t) { Time* p = OnePtr(); p->time += t; return *this; }
		/**@brief 重载算数运算符*/
		PTime&operator-=(long long t) { Time* p = OnePtr(); p->time -= t;  return *this; }
		/**@brief 重载算数运算符*/
		PTime&operator%=(long long t) { Time* p = OnePtr(); p->time %= t; return *this; }
		/**@brief 重载算数运算符*/
		PTime&operator*=(long long t) { Time* p = OnePtr(); p->time *= t; return *this; }
		/**@brief 重载算数运算符*/
		PTime&operator/=(long long t) { Time* p = OnePtr(); p->time /= t; return *this; }
		/**@brief 重载算数运算符*/
		friend inline PTime operator+(const PTime t1, const PTime t2) { return PTime(t1.Ptr()->time + t2.Ptr()->time); }
		/**@brief 重载算数运算符*/
		friend inline PTime operator-(const PTime t1, const PTime t2) { return PTime(t1.Ptr()->time - t2.Ptr()->time); }

		/**@brief 赋值运算*/
		PTime& operator=(long long t) { OnePtr()->time = t; return *this; }
		/**
		@brief 获取该时间所在年份
		@note 认为该对象表示时刻*/
		unsigned int GetYear()const { return Ptr()->GetYear(); }
		/**
		@brief 获取该时间所在月份
		@note 认为该对象表示时刻*/
		unsigned int GetMonth()const { return Ptr()->GetMonth(); }
		/**
		@brief 获取该时间所在日
		@note 认为该对象表示时刻*/
		unsigned int GetDay()const { return Ptr()->GetDay(); }
		/**
		@brief 获取该时间表示星期几（0代表星期天）
		@note 认为该对象表示时刻*/
		unsigned int GetDayOfWeek()const { return Ptr()->GetDayOfWeek(); }
		/**
		@brief 获取时
		@note 认为该对象表示时刻*/
		unsigned int GetHour()const { return Ptr()->GetHour(); }
		/**
		@brief 获取分
		@note 认为该对象表示时刻*/
		unsigned int GetMinute()const { return Ptr()->GetMinute(); }
		/**
		@brief 获取秒
		@note 认为该对象表示时刻*/
		unsigned int GetSecond()const { return Ptr()->GetSecond(); }
		/**
		@brief 获取毫秒
		@note 认为该对象表示时刻*/
		unsigned int GetMillisecond()const { return Ptr()->GetMillisecond(); }
		/**
		@brief 获取微秒
		@note 认为该对象表示时刻*/
		unsigned int GetMicrosecond()const { return Ptr()->GetMicrosecond(); }
		/**
		@brief 获取该对象所示总时长（天数，可能为负）*/
		int GetDays()const { return Ptr()->GetDays(); }
		/**
		@brief 获取该对象所示总时长（小时数，可能为负）*/
		int GetHours()const { return Ptr()->GetHours(); }
		/**
		brief 获取该对象所示总时长（分数，可能为负）*/
		long long GetMinutes()const { return Ptr()->GetMinutes(); }
		/**
		@brief 获取该对象所示总时长（秒数，可能为负）*/
		long long GetSeconds()const { return Ptr()->GetSeconds(); }
		/**
		@brief 获取该对象所示总时长（毫秒数，可能为负）*/
		long long GetMilliseconds()const { return Ptr()->GetMilliseconds(); }
		/**
		@brief 获取该对象所示总时长（微秒数，可能为负）*/
		long long GetMicroseconds()const { return Ptr()->GetMicroseconds(); }
		/**
		@brief 设置年
		@note 认为该对象表示时刻*/
		void SetYear(unsigned int t) { Ptr()->SetYear(t); }
		/**
		@brief 设置月
		@note 认为该对象表示时刻*/
		void SetMonth(unsigned int t) { Ptr()->SetMonth(t); }
		/**
		@brief 设置日
		@note 认为该对象表示时刻*/
		void SetDay(unsigned int t) { Ptr()->SetDay(t); }
		/**
		@brief 设置时
		@note 认为该对象表示时刻*/
		void SetHour(unsigned int t) { Ptr()->SetHour(t); }
		/**
		@brief 设置分
		@note 认为该对象表示时刻*/
		void SetMinute(unsigned int t) { Ptr()->SetMinute(t); }
		/**
		@brief 设置秒
		@note 认为该对象表示时刻*/
		void SetSecond(unsigned int t) { Ptr()->SetSecond(t); }
		/**
		@brief 设置毫秒
		@note 认为该对象表示时刻*/
		void SetMillisecond(unsigned int t) { Ptr()->SetMillisecond(t); }
		/**
		@brief 设置微秒
		@note 认为该对象表示时刻*/
		void SetMicrosecond(unsigned int t) { Ptr()->SetMicrosecond(t); }

		/**
		@brief 线程挂起一段时间
		@param [传入]参数t表示间隔时间
		@note 与Sleep不同，该方法相当于定时器，意为每隔时间t就放行一次，内部使用Sleep实现*/
		void Wait(const PTime& t) { OnePtr()->Wait(*t.Ptr()); }


		/**@brief 到字符串的转换（格式化输出）*/
		PString ToString(const PString&s)const;
		/**@brief 到字符串的转换*/
		PString ToString()const { return PObject::ToString(); }
#ifdef _CLR /**@brief 托管支持*/
		/**@brief 从托管的时间转换*/
		PTime(System::DateTime^time) :PObject(new Time(time)) {}
		/**@brief 转换到托管的时间*/
		System::DateTime^ ToDateTime()const { return Ptr()->ToDateTime(); }
#endif
	};
}
#endif
